package com.pisolution.actuator.client.gc;

import org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 用于服务端索取垃圾回收器日志.
 *
 * @author sora
 * @version 0.1.0
 */
@SuppressWarnings("unused")
@RestControllerEndpoint(id = "gc")
public class GCLogEndpoint {
    // -------------------------------------------------------------------------------------------------
    //  日志内容获取
    // -------------------------------------------------------------------------------------------------

    /**
     * 从命令行参数中解析出垃圾回收器日志路径并获取日志文件内容.
     *
     * @param line 需要获取的行数 (最新行).
     *
     * @return 日志文件内容.
     */
    @RequestMapping(method = RequestMethod.GET)
    public GCLog retrieve(@RequestParam(value = "line", required = false, defaultValue = "100") int line) {
        // 1. 尝试从命令行参数中解析出日志文件路径.
        final Optional<String> gcLogPath = ManagementFactory
            .getRuntimeMXBean()
            .getInputArguments()
            .stream()
            .filter(arg -> arg.startsWith("-Xlog"))
            .map(arg -> arg.replace("-Xlog:gc:", "").replace("-Xloggc:", ""))
            .filter(file -> new File(file).exists())
            .findFirst();

        // 2. 如果未发现日志文件 则直接返回.
        if (!gcLogPath.isPresent()) {
            return new GCLog(new ArrayList<>(), 1);
        }

        // 3. 尝试获取日志文件信息.
        final Path gcLogFile = Paths.get(gcLogPath.get());
        try {
            // 4. 计算日志文件行数.
            final long lines = Files.lines(gcLogFile).count();

            return new GCLog(
                Files.lines(gcLogFile).skip(lines - line).limit(line).collect(Collectors.toList()),
                0
            );
        } catch (IOException ignore) {
            return new GCLog(new ArrayList<>(), 2);
        }
    }
}
